#include <amxmodx>
#include <amxmisc>
#include <dprp>
// although the other plugins use engine, we're going to jump
// into much more fakemeta stuff, so we'd might as well make it
// only use it
#include <fakemeta>
#include <sqlx>

new g_CarClassname[] = "dprp_car"

new g_Query[512]

new g_Table[] = "dprp_carmod"

new Handle:g_Sql

new g_Model[33][64]

new p_Damage

new g_Ent[33]

public plugin_init()
{
	new Version[33]
	DPRP_Version(Version,32)
	register_plugin("DeepPurpleRP - Ultimate Car Mod",Version,"Hawk552")
	
	p_Damage = register_cvar("dprp_car_damage","120")
	
	register_forward(FM_Touch,"ForwardTouch")
	//register_forward(FM_SetAbsBox,"ForwardSetAbsBox")
	register_forward(FM_CmdStart,"ForwardCmdStart")
	register_forward(FM_PlayerPreThink,"ForwardPreThink")
	register_forward(FM_UpdateClientData, "ForwardUpdateClientData", 1)
	
	register_touch("player","player","TouchPlayer")
	//register_forward(FM_SetAbsBox,"ForwardSetAbsBox")
	//register_clcmd("update","CmdUpdate")
}

public DPRP_Error(const Reason[])
	pause("d")

public plugin_precache()
{
	new Location[128]
	DPRP_GetConfigsdir(Location,127)
	
	add(Location,127,"/carmod.ini")
	
	new File = fopen(Location,"r")
	if(!File)
		set_fail_state("Could not open file for this map.")
	
	new Buffer[128]
	while(!feof(File))
	{
		fgets(File,Buffer,127)
		
		replace(Buffer,127,"^n","")
		
		if(!file_exists(Buffer))
		{
			log_amx("Warning: file ^"%s^" does not exist. Halting precache (server crash stopped).",Buffer)
			return
		}
		
		precache_model(Buffer)
	}
	
	fclose(File)
}

public plugin_end()
{
	new Players[32],Playersnum
	get_players(Players,Playersnum)
	
	for(new Count;Count < Playersnum;Count++)
		attach_view(Players[Count],Players[Count])
}

public DPRP_Init()
{
	g_Sql = DPRP_SqlHandle()
	
	format(g_Query,511,"CREATE TABLE IF NOT EXISTS %s (model VARCHAR(64),origin VARCHAR(32),angle INT(11),authid VARCHAR(36),name VARCHAR(33))",g_Table)
	SQL_ThreadQuery(g_Sql,"IgnoreHandle",g_Query)
	
	format(g_Query,511,"SELECT * FROM %s",g_Table)
	SQL_ThreadQuery(g_Sql,"CarLoadHandle",g_Query)	
}

public TouchPlayer(Ptr,Ptd)
{
	new Attacker,Victim
	if(g_Model[Ptr][0])
		Attacker = Ptr
	else if(g_Model[Ptd][0])
		Attacker = Ptd
	
	if(!Attacker)
		return
	
	Victim = Ptd ? Ptr : Ptd
	
	//fm_fakedamage(Victim,"Car",get_pcvar_float(p_Damage),DMG_CRUSH)
}

// Thanks to VEN for this
fm_fakedamage(victim, const classname[], Float:takedmgdamage, damagetype) {
	new class[] = "trigger_hurt"
	new entity = engfunc(EngFunc_CreateNamedEntity,engfunc(EngFunc_AllocString,class))
	if (!entity)
		return 0

	new value[16]
	format(value, 15, "%f", takedmgdamage * 2)
	engfunc(EngFunc_SetKeyValue,engfunc(EngFunc_GetInfoKeyBuffer,entity), "dmg", value, class)

	format(value, 15, "%i", damagetype)
	engfunc(EngFunc_SetKeyValue,engfunc(EngFunc_GetInfoKeyBuffer,entity), "damagetype", value, class)

	engfunc(EngFunc_SetKeyValue,engfunc(EngFunc_GetInfoKeyBuffer,entity), "origin", "8192 8192 8192", class)
	dllfunc(DLLFunc_Spawn,entity)

	set_pev(entity, pev_classname, classname)
	dllfunc(DLLFunc_Touch, entity, victim)
	engfunc(EngFunc_RemoveEntity,entity)
	
	return 1
}

public CarLoadHandle(FailState,Handle:Query,Error[],Errcode,Data[],DataSize) 
{
	if(FailState == TQUERY_CONNECT_FAILED)
		return log_amx("Could not connect to SQL database.")//set_fail_state("Could not connect to SQL database.")
	else if(FailState == TQUERY_QUERY_FAILED)
		return log_amx("Internal error: consult developer. - %s, Query: %s",Error,g_Query)
	
	if(Errcode)
		return log_amx("Error on query: %s",Error)
	
	new Float:vAngles[3],Float:Angle,Model[64],Float:Origin[3],Authid[36],Name[33],Temp[64],Cache[3][12],Ent
	while(SQL_MoreResults(Query))
	{
		SQL_ReadResult(Query,0,Model,63)
		SQL_ReadResult(Query,1,Temp,63)
		
		parse(Temp,Cache[0],11,Cache[1],11,Cache[2],11)
		
		for(new Count;Count < 3;Count++)
			Origin[Count] = str_to_float(Cache[Count])
		
		SQL_ReadResult(Query,2,Angle)
		SQL_ReadResult(Query,3,Authid,35)
		SQL_ReadResult(Query,4,Name,32)
		
		Ent = create_entity("info_target")
		if(!Ent)
			set_fail_state("Failed to create car entity.")
		
		vAngles[1] = Angle
		
		set_pev(Ent,pev_classname,g_CarClassname)
		engfunc(EngFunc_SetModel,Ent,Model)
		engfunc(EngFunc_SetOrigin,Ent,Origin)
		set_pev(Ent,pev_solid,SOLID_BBOX)
		engfunc(EngFunc_SetSize,Ent,Float:{-75.0,-26.0,-40.0},Float:{75.0,26.0,26.0})
		set_pev(Ent,pev_angles,vAngles)
		set_pev(Ent,pev_message,Authid)	
		set_pev(Ent,pev_noise,Name)
		set_pev(Ent,pev_movetype,MOVETYPE_FLY)
		//set_pev(Ent,pev_gravity,300.0 / 800.0)
		
		engfunc(EngFunc_DropToFloor,Ent)
		
		SQL_NextRow(Query)
	}
	
	return PLUGIN_CONTINUE
}

public ForwardSetAbsBox(id)
{
	static Float:AbsMins[3],Float:AbsMaxs[3],Float:Mins[3] = {-75.0,-26.0,-40.0},Float:Maxs[3] = {75.0,26.0,26.0}
	pev(id,pev_origin,AbsMins)
	AbsMaxs = AbsMins
		
	for(new Count;Count < 3;Count++)
	{
		AbsMins[Count] += Mins[Count]
		AbsMaxs[Count] += Maxs[Count]
	}

	//	engfunc(EngFunc_SetSize,id,Float:{-75.0,-26.0,-40.0},Float:{75.0,26.0,26.0})
	//	set_pev(id,pev_mins,Float:{-75.0,-26.0,-40.0})
	//	set_pev(id,pev_maxs,Float:{75.0,26.0,26.0})
	set_pev(id,pev_solid,SOLID_BBOX)
	engfunc(EngFunc_SetSize,id,Mins,Maxs)
	
	set_pev(id,pev_mins,Mins)
	set_pev(id,pev_maxs,Maxs)
	set_pev(id,pev_absmin,AbsMins)
	set_pev(id,pev_absmax,AbsMaxs)
	dllfunc(DLLFunc_SetAbsBox,id)
		
		//return FMRES_SUPERCEDE
	
	//return FMRES_IGNORED
}

public ForwardCmdStart(id,UCHandle,Seed) 
{
	if(!is_user_alive(id) || !g_Model[id][0]) 
		return FMRES_IGNORED
    
	set_uc(UCHandle,UC_Buttons,get_uc(UCHandle,UC_Buttons) & ~IN_ATTACK & ~IN_JUMP & ~IN_DUCK & ~IN_ATTACK2 & ~IN_ALT1 & ~IN_MOVELEFT & ~IN_MOVERIGHT & ~IN_RELOAD)
	
	return FMRES_HANDLED
}

public ForwardUpdateClientData(id,SendWeapons,CdHandle)
{
	if(!is_user_alive(id) || !g_Model[id][0])
		return FMRES_IGNORED
	    
	set_cd(CdHandle,CD_ID,0)  
	    
	return FMRES_HANDLED
}

public ForwardPreThink(id)
{		
	new Button = pev(id,pev_button)
	
	if(g_Ent[id])
	{
		//new Button = pev(id,pev_buttons)
		//if(Button & IN_MOVELEFT)
		//{
			
			
		//}
			
		new Float:Angles[3]
		
		//pev(g_Ent[id],pev_origin,Angles)
		//engfunc(EngFunc_SetOrigin,id,Angles)
		
		pev(g_Ent[id],pev_angles,Angles)
		//set_pev(id,pev_angles,Angles)
		
		ForwardSetAbsBox(g_Ent[id])
		
		new Float:Velocity[3]
		pev(g_Ent[id],pev_velocity,Velocity)
		
		if(Button & IN_FORWARD)
		{
			new Float:Forward[3],Float:Origin[3],Float:Start[3],Float:End[3],Float:Trace
			engfunc(EngFunc_MakeVectors,Angles)
			global_get(glb_v_forward,Forward)
			
			pev(g_Ent[id],pev_origin,Origin)
			
			Start = Origin
			for(new Count;Count < 3;Count++)
				Velocity[Count] = Origin[Count] + Forward[Count] * 20
			
			engfunc(EngFunc_TraceLine,Start,End,1,-1,0)
			get_tr2(0,TR_vecEndPos,Trace)
		
			//return pev_valid(ent) ? ent : 0
		}	
		if(Button & IN_MOVELEFT)
		{
			Angles[1] += 5
			set_pev(g_Ent[id],pev_angles,Angles)
		}
		if(Button & IN_MOVERIGHT)
		{
			Angles[1] -= 5
			set_pev(g_Ent[id],pev_angles,Angles)
		}
		if(Button & IN_BACK)
		{
			new Float:Forward[3],Float:Origin[3],Float:Start[3],Float:End[3],Float:Trace
			engfunc(EngFunc_MakeVectors,Angles)
			global_get(glb_v_forward,Forward)
			
			pev(g_Ent[id],pev_origin,Origin)
			
			Start = Origin
			for(new Count;Count < 3;Count++)
				Velocity[Count] = -(Origin[Count] + Forward[Count] * 20)
			
			engfunc(EngFunc_TraceLine,Start,End,1,-1,0)
			get_tr2(0,TR_vecEndPos,Trace)
			//return pev_valid(ent) ? ent : 0
		}
		
		for(new Count;Count < 3;Count++)
		{
			Velocity[Count] = float(clamp(floatround(Velocity[Count]),-200,200))
			Velocity[Count] += Velocity[Count] > 0 ? -1 : 1
		}
		
		set_pev(g_Ent[id],pev_velocity,Velocity)
	}
	
	static Index,Body,Classname[36]
	get_user_aiming(id,Index,Body,200)
	
	if((!Index || !is_valid_ent(Index)) && g_Model[id][0])
		return
		
	if(Index)
	{
		pev(Index,pev_classname,Classname,35)
		
		if(equali(Classname,g_CarClassname))
		{
			static Name[33]
			pev(Index,pev_noise,Name,32)
			
			client_print(id,print_center,"Owner: %s",Name)
		}
	}
	
	if(Button & IN_USE && !(pev(id,pev_oldbuttons) & IN_USE))
	{	
		if(Index && !g_Model[id][0] && equali(Classname,g_CarClassname))
		{			
			static Authid[36]
			pev(Index,pev_message,Authid,35)
			get_user_authid(id,Classname,35)
			
			if(equali(Classname,Authid))
			{
				new Float:Origin[3],Float:Angles[3],Model[64]
				pev(Index,pev_origin,Origin)
				pev(Index,pev_angles,Angles)
				//pev(Index,pev_model,Model,63)
				
				Origin[2] += 30.0
				
				//remove_filepath(Model,Model,63)
				//replace(Model,63,".mdl","")
				
				engfunc(EngFunc_SetOrigin,id,Origin)
				set_pev(id,pev_angles,Angles)
				set_pev(id,pev_gravity,0.5)
				set_pev(id,pev_friction,0.2)
				
				set_pev(Index,pev_owner,id)
				engfunc(EngFunc_SetOrigin,id,Float:{4096.0,4096.0,4096.0})
				//set_pev(Index,pev_aiment,id)
				//set_pev(Index,pev_movetype,MOVETYPE_FOLLOW)
				
				g_Ent[id] = Index
				
				attach_view(id,g_Ent[id])
				
				//copy(g_Model[id],63,Model)
				//set_user_info(id,"model",Model)
				
				//engfunc(EngFunc_RemoveEntity,Index)
				
				client_print(id,print_chat,"[DPRP] You have gotten into the car.")
			}
		}
		else
		{
			
		}
	}
}		

public ForwardTouch(Ptr,Ptd)
{
	static Classname[33]
	pev(Ptr,pev_classname,Classname,32)
	
	if(equali(Classname,g_CarClassname))
	{
		//UpdateCar(Ptr)
		return
	}
	
	pev(Ptd,pev_classname,Classname,32)
	if(equali(Classname,g_CarClassname))
	{
		//UpdateCar(Ptr)
		return
	}	
}

/*UpdateCar(Ent)
{
new Name[33],Float:Angle,Float:Origin[3],Temp[64],Model[64],Authid[36]
pev(Ent,pev_noise,Name,32)
pev(Ent,pev_angles,Origin)
Angle = Origin[1]
pev(Ent,pev_origin,Origin)
pev(Ent,pev_model,Model,63)
pev(Ent,pev_message,Authid,35)

format(Temp,63,"%d %d %d",floatround(Origin[0]),floatround(Origin[1]),floatround(Origin[2]))

new Mapname[33]
get_mapname(Mapname,32)

new Filename[96]
get_configsdir(Filename,95)

format(Filename,95,"%s/%s/%s.ini",Filename,g_File,Mapname)

new File = fopen(Filename,"r")
if(!File)
	set_fail_state("Could not find file for this map.")
	
	new Buffer[128],Erase,Charnum
	while(!feof(File))
	{	
		fgets(File,Buffer,127)
		
		if(Erase == 1)
		{
			if(containi(Buffer,"[END]") != -1)
				Erase = 2
			
			fseek(File,SEEK_SET,Charnum)
			
			fprintf(File,"")
		}
		else if(Erase == 2)
		{
			//fseek(File,0,SEEK_END)
			
			fprintf(File,"%s^norigin ^"%s^"^nmodel ^"%s^"^nangle ^"%f^"^nowner ^"%s^"^n[END]",Name,Temp,Model,Angle,Authid)
			
			return SUCCEEDED
		}
		
		if(containi(Buffer,Name) != -1)
		{
			Erase = 1
			
			fseek(File,Charnum,SEEK_SET)			
			fprintf(File,"")
		}
		
		Charnum += strlen(Buffer)
	}
	
	return FAILED
}*/

public IgnoreHandle(FailState,Handle:Query,Error[],Errcode,Data[],DataSize) 
{
	if(FailState == TQUERY_CONNECT_FAILED)
		return DPRP_ThrowError(1,g_Query,"Could not connect to SQL database.")
	else if(FailState == TQUERY_QUERY_FAILED)
	{
		static Temp[512]
		SQL_GetQueryString(Query,Temp,511)
		DPRP_ThrowError(1,"Query: %s",Temp)
		
		SQL_QueryError(Query,Temp,511)
		return DPRP_ThrowError(1,"Error: %s",Temp)
	}
	
	if(Errcode)
		return DPRP_ThrowError(1,"Error on query: %s",Error)
	
	return PLUGIN_CONTINUE
}
